#include "vl_support.h"

using namespace VL;

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:23:34
 * 
 * 定义不支持的动作类型切面
 */
std::shared_ptr<VLSupport> VLSupport::instance = std::shared_ptr<VLSupport>(new VLSupport(VLSupport::Aspect::NotSupport));

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:12:56
 * 
 * 保护构造函数, 不允许直接实例化
 * 
 * @param aspect 需要指定动作切面类型
 */
VLSupport::VLSupport(VLSupport::Aspect aspect): aspect(aspect) {

}

/**
 * @Author: CimZzz
 * @Date: 2022-08-19 15:53:54
 * 
 * 执行动作
 * 
 * @param env 环境变量
 */
void VLSupport::doAction(VLEnv* env) {
	this->notImplementation("doAction");
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:17:16
 * 
 * 获取动作切面类型
 * 
 * @return 动作切面类型
 */
VLSupport::Aspect VLSupport::getAspect() const {
	return this->aspect;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:17:41
 * 
 * 判断当前是否为不支持的动作类型
 * 
 * @return 如果是返回 true
 */
bool VLSupport::isNotSupport() {
	return this->aspect == VLSupport::Aspect::NotSupport;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:17:41
 * 
 * 判断当前是否为生成的动作类型
 * 
 * @return 如果是返回 true
 */
bool VLSupport::isGenerate() {
	return this->aspect == VLSupport::Aspect::Generate;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:17:41
 * 
 * 判断当前是否为编译的动作类型
 * 
 * @return 如果是返回 true
 */
bool VLSupport::isCompile() {
	return this->aspect == VLSupport::Aspect::Compile;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-13 15:53:48
 * 
 * 判断当前是否为依赖的动作类型
 * 
 * @return 如果是返回 ture
 */
bool VLSupport::isDependency() {
	return this->aspect == VLSupport::Aspect::Dependency;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-19 15:26:27
 * 
 * 判断当前是否为配置的动作类型
 * 
 * @return 如果是返回 true
 */
bool VLSupport::isConfigure() {
	return this->aspect == VLSupport::Aspect::Configure;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 14:57:00
 * 
 * 抛出异常
 * 
 * @param fmt 异常信息格式化
 * @param ... 不定长消息参数
 */
void VLSupport::throwException(const char * fmt, ...) {
	va_list va;
	va_start(va, fmt);
	VLException exception(this->getTopic(), fmt, va);
	va_end(va);
	throw exception;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-05 17:17:43
 * 
 * 制造异常
 * 
 * @param fmt 异常信息格式化
 * @param ... 不定长消息参数
 */
VLException* VLSupport::makeException(const char * fmt, ...) {
	va_list va;
	va_start(va, fmt);
	VLException* exception = new VLException(this->getTopic(), fmt, va);
	va_end(va);
	return exception;
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-19 15:42:49
 * 
 * 初始化项目工程目录信息
 * 
 * @param env 环境变量
 * 
 * @return 如果项目存在返回 true
 */
bool VLSupport::initProject(VLEnv* env) {
	env->initProject();
	
	return env->projectProperties->isProjectExist;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-19 15:42:49
 * 
 * 初始化项目工程目录信息, 项目必须存在, 否则抛出异常
 * 
 * @param env 环境变量
 */
void VLSupport::initProjectMustExist(VLEnv* env) {
	env->initProject();
	
	if(!env->projectProperties->isProjectExist) {
		this->throwException("project not an valid vl-style project");
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:21:30
 * 
 * 获取不支持的动作切面类型单例
 * 
 * @return 不支持的动作切面类型单例
 */
std::shared_ptr<VLSupport> VLSupport::getNotSupportInstance() {
	return VLSupport::instance;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:33:01
 * 
 * 方法未实现
 * 
 * @param methodName 方法名
 * 
 * @note 抛出方法未实现的异常
 */
void VLSupport::notImplementation(const char * methodName) {
	throw VLException(this->getTopic(), methodName);
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 18:04:21
 * 
 * 加载单参数或复合参数
 * 
 * @param prop 属性指针
 * @param separator 组合分隔符
 */
std::string VLSupport::loadSingleOrMultiParams(std::shared_ptr<VLProp> prop, const char * separator) {
	switch(prop->getType()) {
		case VLProp::PropType::Node : return prop->getValue();
		case VLProp::PropType::Array: {
			ArrayProp* arrayProp = (ArrayProp *) prop.get();
			std::string flags;
			unsigned int size = arrayProp->size();
			for(int i = 0 ; i < size ; i ++) {
				if(i != 0) {
					flags += separator;
				}
				flags += (*arrayProp)[i]->getValue();
			}
			return flags;
		}
		default: return "";
	}
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-04 11:36:55
 * 
 * 获取当前动作切面名
 * 
 * @return 返回当前动作切面名
 */
const char * VLSupport::getTopic() const {
	switch(this->getAspect()) {
		case VLSupport::Aspect::Compile:
			return "Compile";
		case VLSupport::Aspect::Generate:
			return "Generate";
		case VLSupport::Aspect::Dependency:
			return "Dependency";
		case VLSupport::Aspect::Configure:
			return "Configure";
		case VLSupport::Aspect::Dirty:
			return "Dirty";
		default: return "Unknown";
	}
}